/*
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//      Copyright (c) 2007 Intel Corporation. All Rights Reserved.
//
//
*/
#include "umc_defs.h"
#if defined (UMC_ENABLE_DVHD_VIDEO_DECODER)

#include "umc_dv100_decoder.h"
#include <ippvc.h>

namespace UMC
{

static
Ipp8u SaturateByte(Ipp32s iValue)
{
    if (255 < iValue)
        return 255;
    else if (0 > iValue)
        return 0;

    return ((Ipp8u) iValue);

} /* Ipp8u SaturateByte(Ipp32s iValue) */

#undef WRITE_2PIXELS
#define WRITE_2PIXELS(pointer_dst, pointer_y, pointer_u, pointer_v) \
    (pointer_dst)[0] = SaturateByte( *(pointer_y) + 128 );     \
    (pointer_dst)[1] = SaturateByte( *(pointer_u) + 128 );     \
    (pointer_dst)[2] = SaturateByte( *(pointer_y+1) + 128 );   \
    (pointer_dst)[3] = SaturateByte( *(pointer_v) + 128 );

#define WRITE_2PIXELS_UYVY(pointer_dst, pointer_y, pointer_u, pointer_v) \
    (pointer_dst)[0] = SaturateByte( *(pointer_u) + 128 );     \
    (pointer_dst)[1] = SaturateByte( *(pointer_y) + 128 );     \
    (pointer_dst)[2] = SaturateByte( *(pointer_v) + 128 );   \
    (pointer_dst)[3] = SaturateByte( *(pointer_y+1) + 128 );

#define WRITE_4AVERAGED_PIXELS(pointer_dst, pointer_y, pointer_u, pointer_v) \
        (pointer_dst)[0] = SaturateByte( (Ipp32s)(*(pointer_y + 0) + 128 + *(pointer_y + 1) + 128 +   \
                                         *(pointer_y + 0 + 4) + 128 + *(pointer_y + 1 + 4) + 128)/4 );\
        (pointer_dst)[1] = SaturateByte( (Ipp32s)(*(pointer_u + 0) + 128 + *(pointer_u + 1) + 128 +   \
                                         *(pointer_u + 0 + 4) + 128 + *(pointer_u + 1 + 4) + 128)/4 );\
        (pointer_dst)[2] = SaturateByte( (Ipp32s)(*(pointer_y + 2) + 128 + *(pointer_y + 3) + 128 +   \
                                         *(pointer_y + 2 + 4) + 128 + *(pointer_y + 3 + 4) + 128)/4 );\
        (pointer_dst)[3] = SaturateByte((Ipp32s)(*(pointer_v + 0) + 128 + *(pointer_v + 1) + 128 +    \
                                         *(pointer_v + 0 + 4) + 128 + *(pointer_v + 1 + 4) + 128)/4 );

void QuarterResolutionStoreYCrCb422ToYCbCr422_DV100_16s8u_P3C2R (const Ipp16s* pSrc,
                                                                    Ipp8u *pDst[10],
                                                                     Ipp32s dstStep)
{
    Ipp32s MBNum;
    const Ipp16s *pCurrDCTBlockData, *pY0, *pY1, *pCr, *pCb;
    Ipp8u *pCurrDst;

    //IPP_BAD_PTR2_RET(pSrc, pDst);

    for(MBNum = 0; MBNum < 5; MBNum++)
    {
        Ipp32s LineNum, ColNum;
        pCurrDCTBlockData = pSrc + MBNum * 64 * 8;
        pY0 = pCurrDCTBlockData + 64*0;
        pY1 = pCurrDCTBlockData + 64*1;
        pCr = pCurrDCTBlockData + 64*4;
        pCb = pCurrDCTBlockData + 64*6;

        pCurrDst = pDst[2*MBNum];
        /* Write lumma from DCT0 and DCT1, Cr from DCT4, Cb from DCT6 */
        for(LineNum = 0; LineNum < 4; LineNum++)
        {
            for(ColNum = 0; ColNum < 2; ColNum++)
            {
                WRITE_2PIXELS(pCurrDst + 4*ColNum, pY0 + 2*ColNum, pCb + ColNum, pCr + ColNum);
                WRITE_2PIXELS(pCurrDst + 8 + 4*ColNum, pY1 + 2*ColNum, pCb + 2 + ColNum, pCr + 2+ ColNum);
            }
            pCurrDst += dstStep;
            pY0 += 4;
            pY1 += 4;
            pCb += 4;
            pCr += 4;
        }

        pY0 = pCurrDCTBlockData + 64*2;
        pY1 = pCurrDCTBlockData + 64*3;
        pCr = pCurrDCTBlockData + 64*5;
        pCb = pCurrDCTBlockData + 64*7;
        pCurrDst = pDst[2*MBNum+1];
        /* Write lumma from DCT2 and DCT3, Cr from DCT5, Cb from DCT7 */
        for(LineNum = 0; LineNum < 4; LineNum++)
        {
            for(ColNum = 0; ColNum < 2; ColNum++)
            {
                WRITE_2PIXELS(pCurrDst + 4*ColNum, pY0 + 2*ColNum, pCb + ColNum, pCr + ColNum);
                WRITE_2PIXELS(pCurrDst + 8 + 4*ColNum, pY1 + 2*ColNum, pCb + 2 + ColNum, pCr + 2+ ColNum);
            }
            pCurrDst += dstStep;
            pY0 += 4;
            pY1 += 4;
            pCb += 4;
            pCr += 4;
        }
    }

}

void Resolution8x8To4x4To2x2StoreYCrCb422ToYCbCr422_DV100_16s8u_P3C2R (const Ipp16s* pSrc,
                                                                    Ipp8u *pDst[10],
                                                                     Ipp32s dstStep)
{
    Ipp32s MBNum;
    const Ipp16s *pCurrDCTBlockData, *pY0, *pY1, *pCr, *pCb;
    Ipp8u *pCurrDst;

    for(MBNum = 0; MBNum < 5; MBNum++)
    {
        //Ipp32s LineNum, ColNum;
        pCurrDCTBlockData = pSrc + MBNum * 64 * 8;
        pY0 = pCurrDCTBlockData + 64*0;
        pY1 = pCurrDCTBlockData + 64*1;
        pCr = pCurrDCTBlockData + 64*4;
        pCb = pCurrDCTBlockData + 64*6;

        pCurrDst = pDst[2*MBNum];

        WRITE_4AVERAGED_PIXELS(pCurrDst, pY0, pCb, pCr);
        WRITE_4AVERAGED_PIXELS(pCurrDst + 4, pY1, pCb + 2, pCr + 2);
        pCurrDst += dstStep;
        WRITE_4AVERAGED_PIXELS(pCurrDst, pY0 + 8, pCb + 8, pCr + 8);
        WRITE_4AVERAGED_PIXELS(pCurrDst + 4, pY1 + 8, pCb + 2 + 8, pCr + 2 + 8);

        pY0 = pCurrDCTBlockData + 64*2;
        pY1 = pCurrDCTBlockData + 64*3;
        pCr = pCurrDCTBlockData + 64*5;
        pCb = pCurrDCTBlockData + 64*7;

        pCurrDst = pDst[2*MBNum+1];
        WRITE_4AVERAGED_PIXELS(pCurrDst, pY0, pCb, pCr);
        WRITE_4AVERAGED_PIXELS(pCurrDst + 4, pY1, pCb + 2, pCr + 2);
        pCurrDst += dstStep;
        WRITE_4AVERAGED_PIXELS(pCurrDst, pY0 + 8, pCb + 8, pCr + 8);
        WRITE_4AVERAGED_PIXELS(pCurrDst + 4, pY1 + 8, pCb + 2 + 8, pCr + 2 + 8);
    }

}

void DCOnlyStoreYCrCb422ToYCbCr422_DV100_16s8u_P3C2R (const Ipp16s* pSrc,
                                                            Ipp8u *pDst[10]/*,
                                                            Ipp32s dstStep*/)
{
    Ipp32s MBNum;
    const Ipp16s *pCurrDCTBlockData, *pY0, *pY1, *pCr, *pCb;
    Ipp8u *pCurrDst;

    for(MBNum = 0; MBNum < 5; MBNum++)
    {
        //Ipp32s LineNum, ColNum;
        pCurrDCTBlockData = pSrc + MBNum * 64 * 8;
        pY0 = pCurrDCTBlockData + 64*0;
        pY1 = pCurrDCTBlockData + 64*1;
        pCr = pCurrDCTBlockData + 64*4;
        pCb = pCurrDCTBlockData + 64*6;

        pCurrDst = pDst[2*MBNum];

        pCurrDst[0] = SaturateByte( *(pY0) + 128 );
        pCurrDst[1] = SaturateByte( *(pCb) + 128 );
        pCurrDst[2] = SaturateByte( *(pY1) + 128 );
        pCurrDst[3] = SaturateByte( *(pCr) + 128 );

        pY0 = pCurrDCTBlockData + 64*2;
        pY1 = pCurrDCTBlockData + 64*3;
        pCr = pCurrDCTBlockData + 64*5;
        pCb = pCurrDCTBlockData + 64*7;

        pCurrDst = pDst[2*MBNum+1];

        pCurrDst[0] = SaturateByte( *(pY0) + 128 );
        pCurrDst[1] = SaturateByte( *(pCb) + 128 );
        pCurrDst[2] = SaturateByte( *(pY1) + 128 );
        pCurrDst[3] = SaturateByte( *(pCr) + 128 );
    }

}

void Resolution8x8To8x4StoreYCrCb422ToYCbCr422_DV100_16s8u_P3C2R (const Ipp16s* pSrc,
                                                                             Ipp8u *pDst[10],
                                                                             Ipp32s dstStep)
{
    Ipp32s MBNum;
    Ipp16s *pCurrDCTBlockData, *pY0, *pY1, *pCr, *pCb;
    Ipp8u *pCurrDst;

    //Perform averaging: from 8x8 to 8x4
    Ipp16s *pCurrDCTBlock = (Ipp16s *)pSrc;
    for (Ipp32s block8x8Number = 0; block8x8Number < 40; block8x8Number++)
    {
        ippsAdd_16s_ISfs(pCurrDCTBlock + 8, pCurrDCTBlock, 8, 1);
        ippsAdd_16s_Sfs(pCurrDCTBlock + 16, pCurrDCTBlock + 24, pCurrDCTBlock +  8, 8, 1);
        ippsAdd_16s_Sfs(pCurrDCTBlock + 32, pCurrDCTBlock + 40, pCurrDCTBlock + 16, 8, 1);
        ippsAdd_16s_Sfs(pCurrDCTBlock + 48, pCurrDCTBlock + 56, pCurrDCTBlock + 24, 8, 1);
        //ippsZero_16s(pCurrDCTBlock + 32, 32);
        pCurrDCTBlock += 64;
    }

    for(MBNum = 0; MBNum < 5; MBNum++)
    {
        Ipp32s LineNum, ColNum;
        pCurrDCTBlockData = (Ipp16s *)pSrc + MBNum * 64 * 8;
        pY0 = pCurrDCTBlockData + 64*0;
        pY1 = pCurrDCTBlockData + 64*1;
        pCr = pCurrDCTBlockData + 64*4;
        pCb = pCurrDCTBlockData + 64*6;

        pCurrDst = pDst[2*MBNum];
        /* Write lumma from DCT0 and DCT1, Cr from DCT4, Cb from DCT6 */
        for(LineNum = 0; LineNum < 4; LineNum++)
        {
            for(ColNum = 0; ColNum < 4; ColNum++)
            {
                WRITE_2PIXELS(pCurrDst + 4*ColNum, pY0 + 2*ColNum, pCb + ColNum, pCr + ColNum);
                WRITE_2PIXELS(pCurrDst + 16 + 4*ColNum, pY1 + 2*ColNum, pCb + 4 + ColNum, pCr + 4 + ColNum);
            }
            pCurrDst += dstStep;
            pY0 += 8;
            pY1 += 8;
            pCb += 8;
            pCr += 8;
        }

        pY0 = pCurrDCTBlockData + 64*2;
        pY1 = pCurrDCTBlockData + 64*3;
        pCr = pCurrDCTBlockData + 64*5;
        pCb = pCurrDCTBlockData + 64*7;
        pCurrDst = pDst[2*MBNum+1];
        /* Write lumma from DCT2 and DCT3, Cr from DCT5, Cb from DCT7 */
        for(LineNum = 0; LineNum < 4; LineNum++)
        {
            for(ColNum = 0; ColNum < 4; ColNum++)
            {
                WRITE_2PIXELS(pCurrDst + 4*ColNum, pY0 + 2*ColNum, pCb + ColNum, pCr + ColNum);
                WRITE_2PIXELS(pCurrDst + 16 + 4*ColNum, pY1 + 2*ColNum, pCb + 4 + ColNum, pCr + 4 + ColNum);
            }
            pCurrDst += dstStep;
            pY0 += 8;
            pY1 += 8;
            pCb += 8;
            pCr += 8;
        }
    }

}

void Resolution8x8To8x2StoreYCrCb422ToYCbCr422_DV100_16s8u_P3C2R (const Ipp16s* pSrc,
                                                                             Ipp8u *pDst[10],
                                                                             Ipp32s dstStep)
{
    Ipp32s MBNum;
    Ipp16s *pCurrDCTBlockData, *pY0, *pY1, *pCr, *pCb;
    Ipp8u *pCurrDst;

    //Perform averaging: from 8x8 to 8x2
    Ipp16s *pCurrDCTBlock = (Ipp16s *)pSrc;
    for (Ipp32s block8x8Number = 0; block8x8Number < 40; block8x8Number++)
    {
        ippsAdd_16s_I(pCurrDCTBlock + 8, pCurrDCTBlock, 8);
        ippsAdd_16s_I(pCurrDCTBlock + 24, pCurrDCTBlock + 16, 8);
        ippsAdd_16s_ISfs(pCurrDCTBlock + 16, pCurrDCTBlock, 8, 2);

        ippsAdd_16s_I(pCurrDCTBlock + 40, pCurrDCTBlock + 32, 8);
        ippsAdd_16s_I(pCurrDCTBlock + 56, pCurrDCTBlock + 48, 8);
        ippsAdd_16s_Sfs(pCurrDCTBlock + 48, pCurrDCTBlock + 32, pCurrDCTBlock + 8, 8, 2);

        //ippsZero_16s(pCurrDCTBlock + 16, 32);
        pCurrDCTBlock += 64;
    }

    for(MBNum = 0; MBNum < 5; MBNum++)
    {
        Ipp32s LineNum, ColNum;
        pCurrDCTBlockData = (Ipp16s *)pSrc + MBNum * 64 * 8;
        pY0 = pCurrDCTBlockData + 64*0;
        pY1 = pCurrDCTBlockData + 64*1;
        pCr = pCurrDCTBlockData + 64*4;
        pCb = pCurrDCTBlockData + 64*6;

        pCurrDst = pDst[2*MBNum];
        /* Write lumma from DCT0 and DCT1, Cr from DCT4, Cb from DCT6 */
        for(LineNum = 0; LineNum < 2; LineNum++)
        {
            for(ColNum = 0; ColNum < 4; ColNum++)
            {
                WRITE_2PIXELS(pCurrDst + 4*ColNum, pY0 + 2*ColNum, pCb + ColNum, pCr + ColNum);
                WRITE_2PIXELS(pCurrDst + 16 + 4*ColNum, pY1 + 2*ColNum, pCb + 4 + ColNum, pCr + 4 + ColNum);
            }
            pCurrDst += dstStep;
            pY0 += 8;
            pY1 += 8;
            pCb += 8;
            pCr += 8;
        }

        pY0 = pCurrDCTBlockData + 64*2;
        pY1 = pCurrDCTBlockData + 64*3;
        pCr = pCurrDCTBlockData + 64*5;
        pCb = pCurrDCTBlockData + 64*7;
        pCurrDst = pDst[2*MBNum+1];
        /* Write lumma from DCT2 and DCT3, Cr from DCT5, Cb from DCT7 */
        for(LineNum = 0; LineNum < 2; LineNum++)
        {
            for(ColNum = 0; ColNum < 4; ColNum++)
            {
                WRITE_2PIXELS(pCurrDst + 4*ColNum, pY0 + 2*ColNum, pCb + ColNum, pCr + ColNum);
                WRITE_2PIXELS(pCurrDst + 16 + 4*ColNum, pY1 + 2*ColNum, pCb + 4 + ColNum, pCr + 4 + ColNum);
            }
            pCurrDst += dstStep;
            pY0 += 8;
            pY1 += 8;
            pCb += 8;
            pCr += 8;
        }
    }

}

}//namespace UMC


#endif //(UMC_ENABLE_DVHD_VIDEO_DECODER)
